package handler;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.crypto.Cipher;

/**
 * The Database DAO is setup to allow equations to be loaded and saved
 * to the Database in a unified fashion.  It implements the NotebookDAO
 * along with the other DAO's.
 * 
 * @author David Hietpas
 */
public class DBDAO implements NotebookDAO {

    private DBHandler dbh;
    private int fileId;
    private int userId;
    private String filename;
    private String password;
    private EncryptionHandler encryptionHandler;
    private XMLHandler xmlHandler;

    
    public DBDAO(int fileId, int userId, String filename, String password) {
        this.fileId = fileId;
        this.userId = userId;
        this.filename = filename;
        this.password = password;
        dbh = new DBHandler();
        encryptionHandler = new EncryptionHandler();
        this.xmlHandler = new XMLHandler();
    }

    /**
     * Gets the equations from the Database and returns a list.
     * 
     * @return List<EquateNode>
     */
    @Override
    public List<EquateNode> getEquations() {
        
        byte[] privateKey;
        InputStream is = null;
        
        try {
            is = new FileInputStream("p.dat");
            File file = new File("p.dat");
            privateKey = new byte[(int)file.length()];
            is.read(privateKey);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if(is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
       
        Permissions permissions = dbh.getNotebookFilePermissions(fileId, userId);
        byte[] encryptedDes = permissions.getDesKey();
        
        System.out.println(encryptedDes + "" );
        ByteArrayOutputStream outputDes = new ByteArrayOutputStream();
        
        this.encryptionHandler.decryptRSA(privateKey, new ByteArrayInputStream(encryptedDes), outputDes);
        
        NotebookFile file = dbh.getNotebookFileByNotebookFileId(fileId);
        file.Lock(userId);
        file.update(); // update lock
        
        ByteArrayInputStream input = new ByteArrayInputStream(file.getNotebookFile());
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        this.encryptionHandler.decryptDES(outputDes.toString(), input, output);
        
        return this.xmlHandler.getEquations(new ByteArrayInputStream(output.toByteArray()));
    }

    /**
     * Saves the passed in Equation list into the Database.
     * 
     * @param List<EquateNode> notebookEquations
     */
    @Override
    public void saveEquations(final List<EquateNode> notebookEquations) {

        NotebookFile file = dbh.getNotebookFileByNotebookFileId(fileId);
        
        ByteArrayOutputStream notebookEquationOutStream = new ByteArrayOutputStream();
        this.xmlHandler.saveEquations(notebookEquations, notebookEquationOutStream);
        
        ByteArrayInputStream notebookEquationInStream = new ByteArrayInputStream(notebookEquationOutStream.toByteArray());
        ByteArrayOutputStream outputDes = new ByteArrayOutputStream();
        this.encryptionHandler.encryptDES(password, notebookEquationInStream, outputDes);
        
        User user = dbh.getUserById(userId);
        ByteArrayInputStream dcrDes =  new ByteArrayInputStream(password.getBytes());
        ByteArrayOutputStream encDes = new ByteArrayOutputStream();
        this.encryptionHandler.encryptRSA(user.getPublicKey(), dcrDes, encDes);
        
        if (file == null) {
            dbh.addNewNotebookFile(new NotebookFile(fileId, filename, outputDes.toByteArray(), userId, -1));
            
            ArrayList<NotebookFile> files = dbh.getNotebookFileByNotebookFileName(filename);
            NotebookFile nbfile = files.get(0);
            
            dbh.addNewPermission(new Permissions(nbfile.getId(),userId,1,encDes.toByteArray()));
        } else {
            file.setNotebookFile(outputDes.toByteArray());
            file.Unlock();
            file.update();
        }

    }

}
